#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

#include <iostream>
using namespace std;

#define SERVER_IP       "192.168.13.45"//服务器ip
#define SERVER_PORT     9999//端口号


int sockfd;//套接字
/************************************
 * 函数名称：TCPinit
 * 
 * 函数功能：连接服务器
 * 
 * 函数参数：None
 * 
 * 返回值：(-1)有错:(0)正确
 * 
 * 注意事项：重复连接服务器时端口号不修改可能会连接不上("connect error")
 * 
 ************************************/
int TCPinit()//初始化连接服务器
{
    //1.创建套接字
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd < 0)
    {
        cout<<"socket error"<<endl;
        return -1;
    }

    //2.连接服务器
    struct sockaddr_in seraddr;
    memset(&seraddr,0,sizeof(seraddr));
    seraddr.sin_family = AF_INET;//地址族
    //
        // int a = 0;
        // cout<<"请输入端口号"<<endl;
        // cin>>a;
        // seraddr.sin_port = htons(a);//端口号
    //
    seraddr.sin_port = htons(9999);//端口号
    seraddr.sin_addr.s_addr = inet_addr("192.168.13.45");//*********************服务器地址
    int ret = connect(sockfd,(struct sockaddr*)&seraddr,sizeof(seraddr));
    if(ret < 0)
    {
        cout<<"connect error"<<endl;
        exit(0);
    }
    return 0;
}


/************************************
 * 函数名称：TCPlogReg
 * 
 * 函数功能：和服务器通信，验证登录的和注册的账号密码是否正确
 * 
 * 函数参数：@acc:账号
 *          @pas:密码
 *          @flag:判断是登录还是注册(0)为注册,(1)为登录
 * 
 * 返回值：注册或登陆成功返回(1)，注册或登陆失败返回(0)
 * 
 * 注意事项：None
 * 
 ************************************/
int TCPlogReg(int acc, int pas,int flag)//登录或注册
{
    if(0 == flag)//0为注册
    {
        char accPas[128] = {0};
        sprintf(accPas,"{sname:acc=%d,pas=%d;flag=%d}",acc,pas,flag);
        int size = send(sockfd, accPas, sizeof(accPas), 0);

        //接收服务器的数据，判断输入的账号是否存在
        int a = -100;
        recv(sockfd,&a,4,0);
        if(0 == a)//注册：0注册成功，1注册失败
        {
            cout<<a<<"注册成功"<<endl;
            return 1;
        }
        else
        {
            cout<<a<<"注册失败,请重新注册"<<endl;
            return 0;
        }
        
    }
    else//1为登录
    {
        char accPas[128] = {0};
        sprintf(accPas,"{sname:acc=%d,pas=%d;flag=%d}",acc,pas,flag);
        send(sockfd,accPas,sizeof(accPas),0);

        //接收服务器的数据，判断输入的账号密码是否正确
        int a = -100;
        recv(sockfd,&a,4,0);//登录：0不正确，1正确。
        if(0 == a)
        {
            cout<<a<<"输入账号密码有误，请重新输入"<<endl;
            return 0;
        }
        else
        {
            cout<<a<<"登陆成功"<<endl;
            return 1;
        }
    }
}


/************************************
 * 函数名称：TCPstartGame
 * 
 * 函数功能：与服务器通信，向服务器发送开始游戏的请求，如果没有玩家，则等待，如果
 *          有玩家则可以开始游戏
 *          (修改1)修改后只需等待服务器返回(1)或(2)即可
 * 函数参数：None
 * 
 * 返回值：(1)为黑棋方，(2)为白棋方
 * 
 * 注意事项：没有玩家时会一直等待(recv()函数会阻塞住程序)，所以程序可能会做不了其他事情 
 *          (也就是退出不了)所以可能需要开一条线程专门等待 
 * 
 ************************************/
int TCPstartGame()
{
    int flag = 0;

    char reqbuf[] = "{gamereq:}";//发送开始协议标识符
    send(sockfd,reqbuf,strlen(reqbuf),0);

    char buf[64] = {0};
    recv(sockfd,buf,sizeof(buf),0);//接收服务器返回的标识符
    cout<<"服务器返回的标识符:"<<buf<<endl;

    char head_x[64] = {0};
    sscanf(buf,"{%[^=]}",head_x);
    if(!strcmp(head_x,"color_flag"))
    {
        sscanf(buf,"{%[^=]=%d}",head_x,&flag);
        return flag;
    }
/*报废
    if(!strcmp("pipei_ing",buf))//这家伙是第一个进入的需要等待，那他必定是黑棋
    {
        while(1)
        {
            //2.等待服务器发送开始标识符过来
            memset(buf,0,sizeof(buf));
            recv(sockfd,buf,sizeof(buf),0);1
            cout<<"等待另一个玩家,服务器发送过来的数据是:"<<buf<<endl;   

            if(!strcmp("pipei_success",buf))//比较服务器发来的数据是否是开始游戏标识符，是则跳出循环
            {
                break;
            }            
        }
        cout<<"双方都进入成功,此方为黑棋玩家"<<endl;
        return 1;
    }
    else//这个是第二个进入的，所以是白棋
    {
        cout<<"双方都进入成功,此方为白棋玩家"<<endl;      
    }
    return 2;
*/
}

/************************************
 * 函数名称：guanzhan
 * 
 * 函数功能：与服务器通信，用户点击观战，等待服务器返回当前房间的数量
 * 
 * 函数参数：None
 * 
 * 返回值：返回房间数量
 * 
 * 注意事项：None
 * 
 ************************************/
int guanzhan()
{
    char guanzhanbuf[] = "{guanzhan:}";//观战协议标识符
    send(sockfd,guanzhanbuf,strlen(guanzhanbuf),0);

    char buf[64] = {0};
    recv(sockfd,buf,sizeof(buf),0);//接收服务器返回的标识符
    //cout<<"服务器返回的标识符:"<<buf<<endl;
    int roomNum = -1;
    sscanf(buf,"{%d}",&roomNum);

    return roomNum;
}

/************************************
 * 函数名称：RoomNo
 * 
 * 函数功能：发送用户点击的房间号给服务器
 * 
 * 函数参数：@number:房间号
 * 
 * 返回值：None
 * 
 * 注意事项：None
 * 
 ************************************/
void RoomNo(int number)
{
    send(sockfd,&number,4,0);
}

/************************************
 * 函数名称：exitGuanzhan
 * 
 * 函数功能：退出观战功能时需要发送退出的请求给服务器
 * 
 * 函数参数：None
 * 
 * 返回值：None
 * 
 * 注意事项：None
 * 
 ************************************/
void exitGuanzhan()
{
    char buf[] = "{GuanTui:}";//退出观战协议标识符
    send(sockfd,buf,strlen(buf),0);
}

/************************************
 * 函数名称：sendCoor
 * 
 * 函数功能：发送用户下棋的坐标给服务器
 * 
 * 函数参数：@x:
 *          @y:      
 *          @flag:
 * 返回值：None
 * 
 * 注意事项：None
 * 
 ************************************/
void sendCoor(int x, int y, int flag)//好像改成客户端判断输赢了，那么传输的时候要加一个flag表示谁赢了
{
    char buf[64] = {0};
    sprintf(buf,"{cor:x=%d,y=%d,flag=%d}",x,y,flag);
    send(sockfd,buf,sizeof(buf),0);
}

/************************************
 * 函数名称：QiPan
 * 
 * 函数功能：接收服务器发送的棋盘，并且返回flag(0)平局(1)黑棋胜(2)白棋胜
 *          (修改1)增加了判断对方是否投降的功能，如果对方投降，则直接返回胜利方
 *           (又修改回去2)胜利win_flag直接在服务器端更新，随整个棋盘发送回来
 * 函数参数：@qipan:整个棋盘，在函数里面直接覆盖更新
 * 
 * 返回值：(0)表示继续进行(1)表示黑棋胜利(2)白棋胜利
 * 
 * 注意事项：None
 * 
 ************************************/
int QiPan(int *qipan)
{
    char temp[256] = {0};
    char cor[225] = {0};
    //int qipan[225] = {0};
    int win_flag = 0;
        
    //2.等待服务器返回整个棋盘和判断对方是否投降
    //解析出坐标和判断输赢两部分，flag在最后，只发送一次
    recv(sockfd,temp,256,0);
    /*报废
        char head_x[32] = {0}; 
        sscanf(temp,"{%[^:]:}",head_x);
        if(!strcmp("success",head_x))//如果头是success则说对方投降，我方胜利，直接return
        {
            sscanf(temp,"{%[^:]:flag=%d}",head_x,&win_flag);
            cout<<"对方投降"<<endl;
            return win_flag;
        }
    */


    sscanf(temp,"%[^,],flag=%d",cor,&win_flag);
    //cout<<cor<<endl;//验证传输是否正确
    for(int i = 0; i < 15; i++)
    {
        for(int j = 0; j < 15; j++)
        {
            qipan[15*i+j] = cor[15*i+j] - '0';//字符串转整形
        }
    }

    if(0 == win_flag)//平局:继续游戏
    {
        cout<<"游戏未分胜负继续进行"<<endl;
    }
    else if(1 == win_flag)//黑棋胜:结束游戏 
    {
        cout<<"黑棋胜:结束游戏"<<endl;
        break;
    }   
    else if(2 == win_flag)//白棋胜:结束游戏
    {
        cout<<"白棋胜:结束游戏"<<endl;
        break;
    } 
    
    return win_flag;
}

/************************************
 * 函数名称：touxiang
 * 
 * 函数功能：游戏中的一方点击投降，向服务器发送
 *
 * 函数参数：@piece:是哪一方点击的投降,黑棋(1)还是白棋(2)
 * 
 * 返回值：None
 * 
 * 注意事项：None
 * 
 ************************************/
void touxiang(int piece)
{
    if( 1 == piece)
    {
        piece = 2;
    }
    else if(2 == piece)
    {
        piece = 1;
    }

    char buf[64] = "{success:flag=}";
    sprintf(buf,"{success:flag=%d}",piece);
    send(sockfd,buf,sizeof(buf),0);//向服务器发送的是胜利一方的棋色

    //char buf1[64] = {0};
    //memset(buf,0,sizeof(buf));
    //recv(sockfd,buf1,sizeof(buf1),0);

}


//剩余，游戏中直接退出，悔棋

                        //游戏中退出
                        //商量后:游戏中退去就是投降，直接发送投降协议即可
// void gameTui()
// {
//     char buf[32] = "{Tui:}";
//     send(sockfd,buf,sizeof(buf),0);
// }

//悔棋
void huiqi()
{
    char buf[64] = "{HuiQi:}";
    send(sockfd,buf,sizeof(buf),0);
}